/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package ve.usb.cep.util;

import org.apache.commons.lang.StringUtils;

import ve.usb.cep.util.sqlWhereException;

/**
 *
 * @author Andras
 */
public class sqlWhere {
    
    private String groupOp;
    private rule[] rules;
    private sqlWhere[] groups;
    private String[][] preparedValues;

    public String getGroupOp(){
        return this.groupOp;
    }
    public void setGroupOp(String groupOp){
        this.groupOp = groupOp;
    }

    public rule[] getRules(){
        return this.rules;
    }
    public void setRules(rule[] rules){
        this.rules = rules;
    }

    public sqlWhere[] getGroups(){
        return this.groups;
    }
    public void setGroups(sqlWhere[] groups){
        this.groups = groups;
    }

    public String toSql(String[] fields, String[] types)
        throws sqlWhereException
    {
        //rewriteEnumConditions(fields, types);
        int i = null != this.rules ? this.rules.length : 0;
        i += null != this.groups ? this.groups.length : 0;
        if (0 == i){
            return "";
        }
        String[] rulesSql = new String[i];
        if (null != this.rules){
            preparedValues = new String[this.rules.length][2];
            i = 0;
            for (sqlWhere.rule r : this.rules){
                String[] res = r.toSql(fields, types);
                rulesSql[i] = res[0];
                preparedValues[i][0] = res[1];
                preparedValues[i][1] = res[2];
                i ++;
            }
        }

        if (null != this.groups){
            for (sqlWhere s : this.groups){
                String v = s.toSql(fields, types);
                if ("".equals(v)) continue;
                rulesSql[i] = "(" + v + ")";
                mergeValues(s.getPreparedValues());
                i ++;
            }
            
        }
        return StringUtils.join(rulesSql, " " + groupOp + " ");
    }

    private void mergeValues(String[][] values){
        int i = values.length + (null != preparedValues ? preparedValues.length : 0);
        String[][] tmpValues = new String[i][2];
        i = 0;
        if (null != preparedValues){
            for (String[] v : preparedValues){
                tmpValues[i ++] = v;
            }
        }
        for (String[] v : values){
            tmpValues[i ++] = v;
        }
        preparedValues = tmpValues;
    }
    public String[][] getPreparedValues(){
        return preparedValues;
    }
    /*
     * El objetivo es poder recibir condiciones de like en los enum
     * y convertirlas a condiciones de igualdad/diferencia sobre la base de datos
     * Esto se puede lograr gracias a que los tipos existen como clases.
    protected void rewriteEnumConditions(String[] fields, String[] types)
        throws sqlWhereException
    {
        if (null == rules) return;
        jqgridWhere[] trans = new rule[rules.length];
        int i = 0;
        for (rule r : rules){
            if (!r.isEnum(r.getType(fields, types))) continue;
            trans[i] = new rule();
            trans[i]
            i ++;
        }
     }
     */

    public class rule {
        private String field;
        private String op;
        private String data;

        public String getField(){
            return this.field;
        }
        public void setField(String field){
            this.field = field;
        }

        public String getOp(){
            return this.op;
        }
        public void setOp(String op){
            this.op = op;
        }

        public String getData(){
            return this.data;
        }
        public void setData(String data){
            this.data = data;
        }

        public String getType(String[] fields, String[] types)
            throws sqlWhereException
        {
            int i = 0;
            String type = null;
            for (String f : fields){
                if (f.equals(field)){
                    type = types[i];
                    break;
                }
                i ++;
            }
            if (null == type){
                throw new sqlWhereException("Campo indefinido: " + field);
            }
            return type;
        }
        protected boolean isEnum(String t)
            throws sqlWhereException
        {
            return !"int".equals(t) && !"short".equals(t) && !"String".equals(t);
        }

        protected String[] toSql(String[] fields, String[] types)
            throws sqlWhereException
        {
            String[] res = new String[3];
            res[1] = data;

            int i = 0;
            for (String f : fields){
                if (f.equals(field)){
                    res[2] = types[i];
                    break;
                }
                i ++;
            }
            if (fields.length == i){
                throw new sqlWhereException("Campo indefinido: " + field);
            }

            res[2] = getType(fields, types);
            boolean e = isEnum(res[2]);

            if ("eq".equals(op)){
                res[0] = field + "=" + (e ? "CAST(? AS " + res[2] + ")" : '?');
            }else if("ne".equals(op)){
                res[0] = field + "!=" + (e ? "CAST(? AS " + res[2] + ")" : '?');
            }else if(e){
                throw new sqlWhereException("Los campos tipo lista deben ser comparados por 'igual' o 'no igual'.");
            }else if("le".equals(op)){
                res[0] = field + "<=?";
            }else if("lt".equals(op)){
                res[0] = field + "<?";
            }else if("gt".equals(op)){
                res[0] = field + ">?";
            }else if("ge".equals(op)){
                res[0] = field + ">=?";
            }else if("int".equals(res[2]) || "short".equals(res[2])){
                throw new sqlWhereException("Los campos que no son tipo entero deben ser comparados por 'igual' o 'no igual'.");
            }else if("bw".equals(op)){
                res[0] = field + " ILIKE ?";
                res[1] = '%' + res[1].replaceAll("%", "\\%");
            }else if("bn".equals(op)){
                res[0] = field + " NOT ILIKE ?";
                res[1] = '%' + res[1].replaceAll("%", "\\%");
            }else if("in".equals(op)){
                res[0] = "? ILIKE '%' || " + field + " || '%'";
            }else if("ni".equals(op)){
                res[0] = "? NOT ILIKE '%' || " + field + " || '%'";
            }else if("ew".equals(op)){
                res[0] = field + " ILIKE ?";
                res[1] = res[1].replaceAll("%", "\\%") + '%';
            }else if("en".equals(op)){
                res[0] = field + " NOT ILIKE ?";
                res[1] = res[1].replaceAll("%", "\\%") + '%';
            }else if("cn".equals(op)){
                res[0] = field + " ILIKE ?";
                res[1] = '%' + res[1].replaceAll("%", "\\%") + '%';
            }else if("nc".equals(op)){
                res[0] = field + " NOT ILIKE ?";
                res[1] = '%' + res[1].replaceAll("%", "\\%") + '%';
            }
            return res;
        }
    }
}